package cn.com.acca.ma.service.impl;

import cn.com.acca.ma.model.StockTransactionData;
import com.alibaba.fastjson.JSON;
import java.awt.Color;
import java.awt.Paint;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickMarkPosition;
import org.jfree.chart.axis.DateTickUnit;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.axis.SegmentedTimeline;
import org.jfree.chart.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.CandlestickRenderer;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.time.ohlc.OHLCSeries;
import org.jfree.data.time.ohlc.OHLCSeriesCollection;

import cn.com.acca.ma.common.util.DateUtil;
import cn.com.acca.ma.common.util.PropertiesUtil;
import cn.com.acca.ma.common.util.StringUtil;
import cn.com.acca.ma.enumeration.IndexInfo;
import cn.com.acca.ma.model.StockIndex;
import cn.com.acca.ma.service.StockIndexService;

public class StockIndexServiceImpl extends BaseServiceImpl<StockIndexServiceImpl,StockIndex> implements StockIndexService {

	public StockIndexServiceImpl() {
		super();
	}

	/*********************************************************************************************************************
	 * 
	 * 									                             更新每天的数据  
	 * 
	 *********************************************************************************************************************/
	/**
	 * 更新StockIndex对象某一日的数据
	 * 这个接口不能用了
	 * @param multithreading
	 */
	public void writeStockIndexByDate(boolean multithreading){
		String[] indexCodes = new String[]{IndexInfo.SH_INDEX.getUrlParam(),
			IndexInfo.SZ_INDEX.getUrlParam(), IndexInfo.ZXB_INDEX.getUrlParam(),
			IndexInfo.CYB_INDEX.getUrlParam()};
		
		String stockIndexDate = PropertiesUtil.getValue(STOCK_INDEX_PROPERTIES, "stockIndex.time.date");

		logger.info("从网络上获取指数在【" + stockIndexDate + "】的数据，并插入到stock_index表中");

		List<StockIndex> stockIndexList;
		for(int i=0;i<indexCodes.length;i++){
			String url = DATA_SOURCE_URL_PREFIX_163+indexCodes[i]+"&end="+stockIndexDate+"&start="+stockIndexDate;
			stockIndexList=this.readStockIndex(url,indexCodes[i]);
			this.writeIndexDataText(stockIndexList);
			stockIndexDao.writeStockIndexMyBatis(multithreading);
			System.out.println(url);
		}
	}

	/**
	 * 调用baostock接口，更新StockIndex对象某一日的数据
	 */
	public void writeStockIndexByDate_baoStock(){
		logger.info("调用baostock接口，更新StockIndex对象某一日的数据");

		String stockIndexBeginDate = PropertiesUtil.getValue(STOCK_INDEX_PROPERTIES, "stockIndex.time.beginDate");
		String stockIndexEndDate = PropertiesUtil.getValue(STOCK_INDEX_PROPERTIES, "stockIndex.time.endDate");

		logger.info("从网络上获取指数在【" + stockIndexBeginDate + "】和【" + stockIndexEndDate +
				"】之间的数据，并插入到stock_index表中");

		Process process = null;
		BufferedReader in = null;
		try {
			String[] parameterArray = new String[]{"python",
					DIR + "/src/main/python/dist/adam-python-1.0.tar.gz_files/adam-python-1.0/src/task/collect_stock_index_task.py"};
			process = Runtime.getRuntime().exec(parameterArray);
			in = new BufferedReader(new InputStreamReader(process.getInputStream(), "gbk"));
			String actionStr;
			while ((actionStr = in.readLine()) != null) {
				logger.info(actionStr);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				in.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			process.destroy();
		}
	}

	/**
	 * 根据日期date，计算某一日所有指数的移动平均线数据
	 * @param multithreading
	 */
	public void writeStockIndexMAByDate(boolean multithreading){
		String date = PropertiesUtil.getValue(STOCK_INDEX_PROPERTIES, "stockIndex.movingAverage.date");

		stockIndexDao.writeStockIndexMAByDate(multithreading, date);
	}

	/**
	 * 根据日期date，计算某一日所有指数的Hei Kin Ashi数据
	 * @param multithreading
	 */
	public void writeStockIndexHeiKinAshiByDate(boolean multithreading){
		String date = PropertiesUtil.getValue(STOCK_INDEX_PROPERTIES, "stockIndex.heiKinAshi.date");
		
		stockIndexDao.writeStockIndexHeiKinAshiByDate(multithreading, date);
	}

	/**
	 * 根据日期date，计算所有指数某一日的乖离率
	 * @param multithreading
	 */
	public void writeStockIndexBiasByDate(boolean multithreading){
		String date = PropertiesUtil.getValue(STOCK_INDEX_PROPERTIES, "stockIndex.bias.date");

		stockIndexDao.writeStockIndexBiasByDate(multithreading, date);
	}

	/**
	 * 更新表STOCK_INDEX中某一日的EMA15，EMA26，DIF和DEA字段
	 */
	@Override
	public void writeStockIndexMACDByDate() {
		String date = PropertiesUtil.getValue(STOCK_INDEX_PROPERTIES, "stockIndex.macd.date");

		stockIndexDao.writeStockIndexMACDByDate(date);
	}

	/**
	 * 更新表STOCK_INDEX中某一日的RSV，K和D字段
	 */
	@Override
	public void writeStockIndexKDByDate() {
		String date = PropertiesUtil.getValue(STOCK_INDEX_PROPERTIES, "stockIndex.kd.date");

		stockIndexDao.writeStockIndexKDByDate(date);
	}
	
	/*******************************************************************************************************************
	 * 
	 * 									                             更新每天的图片
	 * 
	 *******************************************************************************************************************/
	/**
	 * 创建StockIndex对象的Hei Kin Ashi图片
	 * @param multithreading
	 */
	@SuppressWarnings({ "deprecation", "static-access" })
	public void createStockIndexHeiKinAshiPicture(boolean multithreading){
		String stockBeginDate = PropertiesUtil.getValue(STOCK_INDEX_PICTURE_PROPERTIES,"stockIndexPicture.beginDate");
		String stockEndDate = PropertiesUtil.getValue(STOCK_INDEX_PICTURE_PROPERTIES,"stockIndexPicture.endDate");
		String stockTimeInterval = PropertiesUtil.getValue(STOCK_INDEX_PICTURE_PROPERTIES, "stockIndexPicture.timeInterval");
		
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");// 设置日期格式
		double kLineMaxValue = Double.MIN_VALUE;// 设置K线数据当中的最大值
		double kLineMinValue = Double.MAX_VALUE;// 设置K线数据当中的最小值
		double amountMaxValue = Double.MIN_VALUE;// 设置成交量的最大值
		double amountMinValue = Double.MAX_VALUE;// 设置成交量的最低值
		
		List<StockIndex> stockIndexList=stockIndexDao.getDataForLineChart(multithreading, stockBeginDate, stockEndDate, "000001");
		if(0==stockIndexList.size()){
			return;
		}
		
		// 获取日期，开盘价，最高价，最低价和收盘价
		OHLCSeries seriesPrice = new OHLCSeries("平均K线图（Hei Kin Ashi）");// 高开低收数据序列，上证指数平均K线图的四个数据，依次是开，高，低，收
		seriesPrice.clear();
		for (int i = 0; i < stockIndexList.size(); i++) {
			seriesPrice.add(new Day(DateUtil.getDateFromDate(stockIndexList.get(i).getDate()),
					DateUtil.getMonthFromDate(stockIndexList.get(i).getDate()),
					DateUtil.getYearFromDate(stockIndexList.get(i).getDate())),
					stockIndexList.get(i).getHAIndexOpenPrice().doubleValue(),
					stockIndexList.get(i).getHAIndexHighestPrice().doubleValue(),
					stockIndexList.get(i).getHAIndexLowestPrice().doubleValue(),
					stockIndexList.get(i).getHAIndexClosePrice().doubleValue());
		}
		for(int i=1;i<=100;i++){
			seriesPrice.add(new Day((0+i)%28+1,
					(0+i)%12+1,
					1900+i),
					2000,
					2000,
					2000,
					2000);
		}
		final OHLCSeriesCollection priceSeriesCollection = new OHLCSeriesCollection();//保留平均K线数据的数据集，必须申明为final，后面要在匿名内部类里面用到
		priceSeriesCollection.addSeries(seriesPrice);
		
		// 获取成交量
		TimeSeries seriesAmount=new TimeSeries("");//对应时间成交量数据
		seriesAmount.clear();
		for(int i=0;i<stockIndexList.size();i++){
			seriesAmount.add(new Day(DateUtil.getDateFromDate(stockIndexList.get(i).getDate()),
					DateUtil.getMonthFromDate(stockIndexList.get(i).getDate()),
					DateUtil.getYearFromDate(stockIndexList.get(i).getDate())),
					stockIndexList.get(i).getVolume());
		}
		for(int i=1;i<=100;i++){
			seriesAmount.add(new Day((0+i)%28+1,
					(0+i)%12+1,
					1900+i),
					1);
		}
		TimeSeriesCollection amountSeriesCollection=new TimeSeriesCollection();//保留成交量数据的集合
		amountSeriesCollection.addSeries(seriesAmount);
		
		//获取平均K线数据的最高值和最低值
		int seriesCountPrice = priceSeriesCollection.getSeriesCount();//一共有多少个序列，目前为一个
		for (int i = 0; i < seriesCountPrice; i++) {
			int itemCount = priceSeriesCollection.getItemCount(i);//每一个序列有多少个数据项
			for (int j = 0; j < itemCount; j++) {
				if (kLineMaxValue < priceSeriesCollection.getHighValue(i, j)) {//取第i个序列中的第j个数据项的最大值
					kLineMaxValue = priceSeriesCollection.getHighValue(i, j);
				}
				if (kLineMinValue > priceSeriesCollection.getLowValue(i, j)) {//取第i个序列中的第j个数据项的最小值
					kLineMinValue = priceSeriesCollection.getLowValue(i, j);
				}
			}
		}
		
		//获取最高值和最低值
		int seriesCountAmount = amountSeriesCollection.getSeriesCount();//一共有多少个序列，目前为一个
		for (int i = 0; i < seriesCountAmount; i++) {
			int itemCount = amountSeriesCollection.getItemCount(i);//每一个序列有多少个数据项
			for (int j = 0; j < itemCount; j++) {
				if (amountMaxValue < amountSeriesCollection.getYValue(i,j)) {//取第i个序列中的第j个数据项的值
					amountMaxValue = amountSeriesCollection.getYValue(i,j);
				}
				if (amountMinValue > amountSeriesCollection.getYValue(i, j)) {//取第i个序列中的第j个数据项的值
					amountMinValue = amountSeriesCollection.getYValue(i, j);
				}
			}
		}
		
		final CandlestickRenderer candlestickRender=new CandlestickRenderer();//设置平均K线图的画图器，必须申明为final，后面要在匿名内部类里面用到
		candlestickRender.setUseOutlinePaint(true); //设置是否使用自定义的边框线，程序自带的边框线的颜色不符合中国股票市场的习惯
		candlestickRender.setAutoWidthMethod(CandlestickRenderer.WIDTHMETHOD_AVERAGE);//设置如何对平均K线图的宽度进行设定
		candlestickRender.setAutoWidthGap(0.001);//设置各个平均K线图之间的间隔
		candlestickRender.setUpPaint(Color.RED);//设置股票上涨的平均K线图颜色
		candlestickRender.setDownPaint(Color.GREEN);//设置股票下跌的平均K线图颜色
		DateAxis x1Axis=new DateAxis();//设置x轴，也就是时间轴
		x1Axis.setAutoRange(false);//设置不采用自动设置时间范围
		try{
			x1Axis.setRange(dateFormat.parse(StringUtil.convertDateStringByFormat(stockBeginDate,"-")),dateFormat.parse(StringUtil.convertDateStringByFormat(String.valueOf(Integer.parseInt(stockTimeInterval)+1), "-")));//设置时间范围，注意时间的最大值要比已有的时间最大值要多一天
		}catch(Exception e){
			e.printStackTrace();
		}
		x1Axis.setTimeline(SegmentedTimeline.newMondayThroughFridayTimeline());//设置时间线显示的规则，用这个方法就摒除掉了周六和周日这些没有交易的日期(很多人都不知道有此方法)，使图形看上去连续
		x1Axis.setAutoTickUnitSelection(false);//设置不采用自动选择刻度值
		x1Axis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);//设置标记的位置
		x1Axis.setStandardTickUnits(DateAxis.createStandardDateTickUnits());//设置标准的时间刻度单位
		x1Axis.setTickUnit(new DateTickUnit(DateTickUnit.DAY,7));//设置时间刻度的间隔，一般以周为单位
		x1Axis.setDateFormatOverride(new SimpleDateFormat("yyyy-MM-dd"));//设置显示时间的格式
		NumberAxis y1Axis=new NumberAxis();//设定y轴，就是数字轴
		y1Axis.setAutoRange(false);//不使用自动设定范围
		y1Axis.setRange(kLineMinValue*0.9, kLineMaxValue*1.1);//设定y轴值的范围，比最低值要低一些，比最大值要大一些，这样图形看起来会美观些
		y1Axis.setTickUnit(new NumberTickUnit((kLineMaxValue*1.1-kLineMinValue*0.9)/10));//设置刻度显示的密度
		XYPlot plot1=new XYPlot(priceSeriesCollection,x1Axis,y1Axis,candlestickRender);//设置画图区域对象
	  
		XYBarRenderer xyBarRender=new XYBarRenderer(){
			private static final long serialVersionUID = 1L;//为了避免出现警告消息，特设定此值
			public Paint getItemPaint(int i, int j){//匿名内部类用来处理当日的成交量柱形图的颜色与平均K线图的颜色保持一致
				if(priceSeriesCollection.getCloseValue(i,j)>priceSeriesCollection.getOpenValue(i,j)){//收盘价高于开盘价，股票上涨，选用股票上涨的颜色
					return candlestickRender.getUpPaint();
				}else{
					return candlestickRender.getDownPaint();
				}
			}
		};
		
		xyBarRender.setMargin(0.1);//设置柱形图之间的间隔
		NumberAxis y2Axis=new NumberAxis();//设置Y轴，为数值,后面的设置，参考上面的y轴设置
		y2Axis.setAutoRange(false);
		y2Axis.setRange(amountMinValue*0.9, amountMaxValue*1.1);
		y2Axis.setTickUnit(new NumberTickUnit((amountMaxValue*1.1-amountMinValue*0.9)/4));
		XYPlot plot2=new XYPlot(amountSeriesCollection,null,y2Axis,xyBarRender);//建立第二个画图区域对象，主要此时的x轴设为了null值，因为要与第一个画图区域对象共享x轴
		CombinedDomainXYPlot combineddomainxyplot = new CombinedDomainXYPlot(x1Axis);//建立一个恰当的联合图形区域对象，以x轴为共享轴
		combineddomainxyplot.add(plot1, 2);//添加图形区域对象，后面的数字是计算这个区域对象应该占据多大的区域2/3
	    combineddomainxyplot.add(plot2, 1);//添加图形区域对象，后面的数字是计算这个区域对象应该占据多大的区域1/3
	    combineddomainxyplot.setGap(10);//设置两个图形区域对象之间的间隔空间
	    JFreeChart chart = new JFreeChart(stockIndexList.get(0).getCode(), JFreeChart.DEFAULT_TITLE_FONT, combineddomainxyplot, false);
	    
	    try {
			FileOutputStream fos = new FileOutputStream(PICTURE_PATH+"stock_index_hei_kin_ashi/"+stockBeginDate+"-"+stockEndDate+"_"+stockIndexList.get(0).getCode()+PICTURE_FORMAT);
			// 将统计图标输出成JPG文件
			ChartUtilities.writeChartAsJPEG(fos, // 输出到哪个输出流
					1, // JPEG图片的质量，0~1之间
					chart, // 统计图标对象
					this.imageWidth, // 宽
					this.IMAGE_HEIGHT, // 高
					null // ChartRenderingInfo 信息
					);
			fos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/*********************************************************************************************************************
	 * 
	 * 									                             更新全部的数据  
	 * 
	 *********************************************************************************************************************/
	public void writeIndexDataText(List<StockIndex> stockIndexList) {
		File file;
		FileWriter fileWriter;
		file = new File(INDEX_DATE);

		file.delete();
		try {
			file.createNewFile();
			fileWriter = new FileWriter(file, true);
			for (StockIndex stockIndex : stockIndexList) {
				fileWriter.append(JSON.toJSONString(stockIndex) + "\n");
			}
			fileWriter.close();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
	}

	/**
	 * 从网络上获取4种指数的数据，然后插入到stock_index表中
	 * @param multithreading
	 */
	public void writeStockIndex(boolean multithreading) {
		String[] indexCodes = new String[]{IndexInfo.SH_INDEX.getUrlParam(),
			IndexInfo.SZ_INDEX.getUrlParam(), IndexInfo.ZXB_INDEX.getUrlParam(),
			IndexInfo.CYB_INDEX.getUrlParam()};
		
		String stockIndexTimeBegin = PropertiesUtil.getValue(STOCK_INDEX_PROPERTIES, "stockIndex.time.begin");
		String stockIndexTimeEnd = PropertiesUtil.getValue(STOCK_INDEX_PROPERTIES, "stockIndex.time.end");

		logger.info("从网络上获取指数从【" + stockIndexTimeBegin + "】到【" + stockIndexTimeEnd + "】的数据，并插入到stock_index表中");

		List<StockIndex> stockIndexList;
		stockIndexDao.deleteStockIndexMyBatis();
		for (int i = 0; i < indexCodes.length; i++) {
			String url = DATA_SOURCE_URL_PREFIX_163 + indexCodes[i] + "&end=" + stockIndexTimeEnd + "&start=" + stockIndexTimeBegin;
			stockIndexList = this.readStockIndex(url, indexCodes[i]);
			this.writeIndexDataText(stockIndexList);
			stockIndexDao.writeStockIndexMyBatis(multithreading);
			System.out.println(url);
		}
	}
	
	public List<StockIndex> readStockIndex(String url, String indexCode) {
		URL realUrl;
		URLConnection connection;
		BufferedReader bufferedReader;
		CSVParser csvparser;
		File file;
		FileWriter fileWriter;
		List<StockIndex> stockIndexList = new ArrayList<>();

		try {
			realUrl = new URL(url);
			connection = realUrl.openConnection();
			connection.connect();
			bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "GBK"));
			csvparser = CSVFormat.EXCEL.parse(bufferedReader);
			List<CSVRecord> csvRecordList = csvparser.getRecords();

			for (int i=1; i<csvRecordList.size(); i++) {
				StockIndex stockIndex = new StockIndex();
				CSVRecord csvRecord = csvRecordList.get(i);

				if (null != csvRecord.get(0) && null != DateUtil.stringToDate(csvRecord.get(0))){
					stockIndex.setDate(DateUtil.stringToDate(csvRecord.get(0)));
				}
				if (null != csvRecord.get(1) && !csvRecord.get(1).equals("") && !csvRecord.get(1).equals("None")){
					stockIndex.setCode(csvRecord.get(1).replace("'", ""));
				}
				if (null != csvRecord.get(3) && !csvRecord.get(3).equals("") && !csvRecord.get(3).equals("None")){
					stockIndex.setClosePrice(new BigDecimal(csvRecord.get(3)));
				}
				if (null != csvRecord.get(4) && !csvRecord.get(4).equals("") && !csvRecord.get(4).equals("None")){
					stockIndex.setHighestPrice(new BigDecimal(csvRecord.get(4)));
				}
				if (null != csvRecord.get(5) && !csvRecord.get(5).equals("") && !csvRecord.get(5).equals("None")){
					stockIndex.setLowestPrice(new BigDecimal(csvRecord.get(5)));
				}
				if (null != csvRecord.get(6) && !csvRecord.get(6).equals("") && !csvRecord.get(6).equals("None")){
					stockIndex.setOpenPrice(new BigDecimal(csvRecord.get(6)));
				}
				if (null != csvRecord.get(8) && !csvRecord.get(8).equals("") && !csvRecord.get(8).equals("None")){
					stockIndex.setChangeAmount(new BigDecimal(csvRecord.get(8)));
				}
				if (null != csvRecord.get(9) && !csvRecord.get(9).equals("") && !csvRecord.get(9).equals("None")){
					stockIndex.setChangeRange(new BigDecimal(csvRecord.get(9)));
				}
				if (null != csvRecord.get(11) && !csvRecord.get(11).equals("") && !csvRecord.get(11).equals("None")){
					stockIndex.setVolume(new BigDecimal(csvRecord.get(11)));
				}
				if (null != csvRecord.get(12) && !csvRecord.get(12).equals("") && !csvRecord.get(12).equals("None")){
					stockIndex.setTurnover(new BigDecimal(csvRecord.get(12)));
				}
				stockIndexList.add(stockIndex);
			}
		} catch (IOException e) {
			file = new File(CONNECTION_EXCEPTION_FILE);

			try {
				if (!file.exists()) {
					file.createNewFile();
				}
				fileWriter = new FileWriter(CONNECTION_EXCEPTION_FILE,true);
				fileWriter.write(new Date() + "       " + url + "\n");
				fileWriter.close();
			} catch (IOException e1) {
				e1.printStackTrace();
			}

			e.printStackTrace();
			List<StockIndex> timeOutList = readStockIndex(url, indexCode);
			for (int i = 0; i < timeOutList.size(); i++) {
				stockIndexList.add(timeOutList.get(i));
			}
		}
		return stockIndexList;
	}

	/**
	 * 计算5、10、20、60、120、250日均线
	 */
	@Override
	public void writeStockIndexMA() {
		stockIndexDao.writeStockIndexMA5();
		stockIndexDao.writeStockIndexMA10();
		stockIndexDao.writeStockIndexMA20();
		stockIndexDao.writeStockIndexMA60();
		stockIndexDao.writeStockIndexMA120();
		stockIndexDao.writeStockIndexMA250();
	}

	/**
	 * 计算Hei Kin Ashi相关的字段
	 */
	public void writeStockIndexHeiKinAshi(){
		stockIndexDao.writeStockIndexHeiKinAshi();
	}

	/**
	 * 计算所有指数的乖离率
	 */
	public void writeStockIndexBias(){
		stockIndexDao.writeStockIndexBias();
	}

	/**
	 * 计算所有指数的MACD
	 */
	@Override
	public void writeStockIndexMACD() {
		stockIndexDao.writeStockIndexMACD();
	}

	/**
	 * 计算所有指数的KD
	 */
	@Override
	public void writeStockIndexKD() {
		stockIndexDao.writeStockIndexKD();
	}

	/**
	 * 将List类型转换为String类型
	 * @param list
	 * @return
	 */
	@Override
	public String listToString(List list) {
		// TODO Auto-generated method stub
		return null;
	}
}
